package com.example.munidingwei

import android.Manifest
import android.content.Context
import android.content.pm.PackageManager
import android.location.Location
import android.location.LocationManager
import androidx.core.app.ActivityCompat
import com.baidu.location.BDAbstractLocationListener
import com.baidu.location.BDLocation
import com.baidu.location.LocationClient
import com.baidu.location.LocationClientOption
import com.baidu.mapapi.SDKInitializer
import com.baidu.mapapi.search.geocode.*
import com.baidu.mapapi.search.poi.*
import com.baidu.mapapi.search.core.PoiInfo
import com.baidu.mapapi.model.LatLng
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.isActive

data class LocationData(
    val latitude: Double,
    val longitude: Double,
    val accuracy: Float,
    val timestamp: Long,
    val isSimulated: Boolean = false,
    val address: String = "", // 详细地址
    val locationName: String = "" // 地点名称（POI）
)

class LocationService(private val context: Context) {
    private val mockLocationProvider = MockLocationProvider(context)
    
    // 后台客户端 - 用于与Python后台通信
    private var backendClient: BackendClient? = null
    
    // 百度地理编码器 - 用于反向地理编码（坐标转地址）
    private val geoCoder: GeoCoder by lazy {
        GeoCoder.newInstance().apply {
            setOnGetGeoCodeResultListener(geoCoderListener)
        }
    }
    
    init {
        // 初始化后台客户端
        initBackendClient()
    }
    
    /**
     * 初始化后台客户端并设置回调
     */
    private fun initBackendClient() {
        try {
            backendClient = MainApplication.getBackendClient(context)
            
            // 设置收到定位请求时的回调
            backendClient?.setOnLocationRequestCallback {
                android.util.Log.d("LocationService", "🎯 后台请求获取位置")
                // 收到后台定位请求时，立即上报当前位置
                getCurrentLocationAndReport()
            }
            
            android.util.Log.d("LocationService", "BackendClient已集成到LocationService")
        } catch (e: Exception) {
            android.util.Log.e("LocationService", "初始化BackendClient失败", e)
        }
    }
    
    /**
     * 连接到后台服务器
     */
    fun connectToBackend(serverUrl: String? = null) {
        try {
            serverUrl?.let { backendClient?.setServerUrl(it) }
            backendClient?.connect()
            android.util.Log.d("LocationService", "正在连接到后台服务器...")
        } catch (e: Exception) {
            android.util.Log.e("LocationService", "连接后台服务器失败", e)
        }
    }
    
    /**
     * 断开后台连接
     */
    fun disconnectFromBackend() {
        backendClient?.disconnect()
        android.util.Log.d("LocationService", "已断开后台连接")
    }
    
    /**
     * 获取当前位置并上报到后台
     */
    private fun getCurrentLocationAndReport() {
        // 先获取当前位置
        getCurrentLocation()
        
        // 如果有当前位置，立即上报
        _currentLocation.value?.let { location ->
            reportLocationToBackend(location)
        }
    }
    
    /**
     * 上报位置到后台
     */
    private fun reportLocationToBackend(locationData: LocationData) {
        try {
            backendClient?.reportLocation(locationData)
            android.util.Log.d("LocationService", "已上报位置到后台: (${locationData.latitude}, ${locationData.longitude})")
        } catch (e: Exception) {
            android.util.Log.e("LocationService", "上报位置失败", e)
        }
    }
    
    // 百度定位客户端 - 延迟初始化
    private var _baiduLocationClient: LocationClient? = null
    
    private fun getBaiduLocationClient(): LocationClient {
        if (_baiduLocationClient == null) {
            // 双重检查，确保SDK已初始化
            LocationClient.setAgreePrivacy(true)
            _baiduLocationClient = LocationClient(context.applicationContext).apply {
                locOption = LocationClientOption().apply {
                    locationMode = LocationClientOption.LocationMode.Hight_Accuracy // 高精度模式
                    setCoorType("bd09ll") // 百度坐标系
                    setScanSpan(0) // 单次定位
                    setIsNeedAddress(true) // 需要地址信息
                    setIsNeedLocationDescribe(true) // 需要位置描述
                    setNeedDeviceDirect(false) // 不需要设备方向
                    setLocationNotify(false) // 不通知定位
                    setIgnoreKillProcess(true) // 后台定位
                    setIsNeedLocationPoiList(true) // 需要POI信息
                    SetIgnoreCacheException(false) // 使用缓存
                    setIsNeedAltitude(false) // 不需要海拔
                }
            }
        }
        return _baiduLocationClient!!
    }
    
    private val _currentLocation = MutableStateFlow<LocationData?>(null)
    val currentLocation: StateFlow<LocationData?> = _currentLocation.asStateFlow()
    
    private val _locationHistory = MutableStateFlow<List<LocationData>>(emptyList())
    val locationHistory: StateFlow<List<LocationData>> = _locationHistory.asStateFlow()
    
    private var isSimulating = false
    private var simulatedLocation: LocationData? = null
    
    // 临时存储等待地理编码的位置数据
    private var pendingLocationData: LocationData? = null
    
    // 协程作用域，用于持续更新模拟位置
    // 使用Dispatchers.IO确保后台也能运行
    private val serviceScope = CoroutineScope(Dispatchers.IO + Job())
    private var updateLocationJob: Job? = null
    
    // 存储当前模拟的坐标
    private var currentMockLatitude: Double = 0.0
    private var currentMockLongitude: Double = 0.0
    private var currentMockAccuracy: Float = 5.0f
    
    // 标记是否正在获取真实位置
    private var isFetchingRealLocation = false
    
    // 搜索结果回调
    private var onSearchResultCallback: ((List<com.example.munidingwei.ui.components.SearchResult>) -> Unit)? = null
    
    // POI搜索监听器
    private val poiSearchListener = object : OnGetPoiSearchResultListener {
        override fun onGetPoiResult(result: PoiResult?) {
            android.util.Log.d("LocationService", "收到POI搜索结果")
            
            if (result == null || result.error != com.baidu.mapapi.search.core.SearchResult.ERRORNO.NO_ERROR) {
                android.util.Log.w("LocationService", "POI搜索失败: ${result?.error}")
                onSearchResultCallback?.invoke(emptyList())
                return
            }
            
            val poiList = result.allPoi
            if (poiList.isNullOrEmpty()) {
                android.util.Log.w("LocationService", "POI搜索无结果")
                onSearchResultCallback?.invoke(emptyList())
                return
            }
            
            // 转换为SearchResult列表
            val searchResults = poiList.map { poi ->
                com.example.munidingwei.ui.components.SearchResult(
                    name = poi.name ?: "未知位置",
                    address = poi.address ?: "",
                    latitude = poi.location.latitude,
                    longitude = poi.location.longitude,
                    city = poi.city ?: ""
                )
            }
            
            android.util.Log.d("LocationService", "POI搜索成功: 找到 ${searchResults.size} 个结果")
            onSearchResultCallback?.invoke(searchResults)
        }
        
        override fun onGetPoiDetailResult(result: PoiDetailResult?) {
            // POI详情结果 - 不需要
        }
        
        override fun onGetPoiDetailResult(result: PoiDetailSearchResult?) {
            // POI详情结果 - 不需要
        }
        
        override fun onGetPoiIndoorResult(result: PoiIndoorResult?) {
            // 室内POI结果 - 不需要
        }
    }
    
    // 地理编码监听器（作为备用）
    private val geoCoderListener = object : OnGetGeoCoderResultListener {
        override fun onGetGeoCodeResult(result: GeoCodeResult?) {
            // 正向地理编码结果（地址转坐标）- 作为POI搜索的备用
            android.util.Log.d("LocationService", "收到地理编码结果")
            
            if (result == null) {
                android.util.Log.w("LocationService", "地理编码失败: 结果为空")
                onSearchResultCallback?.invoke(emptyList())
                return
            }
            
            // 检查是否有错误
            if (result.error != null && result.error.name != "NO_ERROR") {
                android.util.Log.w("LocationService", "地理编码失败: ${result.error}")
                onSearchResultCallback?.invoke(emptyList())
                return
            }
            
            // 获取搜索结果
            val location = result.location
            if (location != null) {
                val searchResult = com.example.munidingwei.ui.components.SearchResult(
                    name = result.address ?: "未知位置",
                    address = result.address ?: "",
                    latitude = location.latitude,
                    longitude = location.longitude
                )
                
                android.util.Log.d("LocationService", "地理编码成功: ${searchResult.name} (${location.latitude}, ${location.longitude})")
                onSearchResultCallback?.invoke(listOf(searchResult))
            } else {
                android.util.Log.w("LocationService", "地理编码结果无坐标")
                onSearchResultCallback?.invoke(emptyList())
            }
        }
        
        override fun onGetReverseGeoCodeResult(result: ReverseGeoCodeResult?) {
            if (result == null) {
                android.util.Log.w("LocationService", "反向地理编码失败: 结果为空")
                // 如果失败，使用没有地址的位置数据
                pendingLocationData?.let { data ->
                    _currentLocation.value = data
                    addToHistory(data)
                }
                return
            }
            
            // 检查是否有错误
            if (result.error != null && result.error.name != "NO_ERROR") {
                android.util.Log.w("LocationService", "反向地理编码失败: ${result.error}")
                pendingLocationData?.let { data ->
                    _currentLocation.value = data
                    addToHistory(data)
                }
                return
            }
            
            // 获取地址信息
            val address = result.address ?: ""
            val poiList = result.poiList
            val locationName = if (poiList != null && poiList.isNotEmpty()) {
                poiList[0].name ?: ""
            } else {
                result.sematicDescription ?: ""
            }
            
            android.util.Log.d("LocationService", "反向地理编码成功: 地址=$address, POI=$locationName")
            
            // 更新位置数据
            pendingLocationData?.let { data ->
                val updatedData = data.copy(
                    address = address,
                    locationName = locationName
                )
                _currentLocation.value = updatedData
                addToHistory(updatedData)
            }
        }
    }
    
    // 百度定位监听器
    private val baiduLocationListener = object : BDAbstractLocationListener() {
        override fun onReceiveLocation(location: BDLocation?) {
            if (location == null) {
                android.util.Log.w("LocationService", "收到空的位置信息")
                return
            }
            
            android.util.Log.d("LocationService", "收到百度定位: locType=${location.locType}, lat=${location.latitude}, lng=${location.longitude}")
            
            if (location.locType == BDLocation.TypeGpsLocation || 
                location.locType == BDLocation.TypeNetWorkLocation ||
                location.locType == BDLocation.TypeOffLineLocation) {
                
                // 获取地址信息
                val address = location.addrStr ?: ""
                val locationName = location.locationDescribe ?: ""
                val city = location.city ?: ""
                val district = location.district ?: ""
                
                // 构建完整地址
                val fullAddress = if (address.isNotEmpty()) {
                    address
                } else {
                    "$city$district"
                }
                
                android.util.Log.d("LocationService", "地址信息: $fullAddress, POI: $locationName")
                    
                    val locationData = LocationData(
                    latitude = location.latitude,
                    longitude = location.longitude,
                    accuracy = location.radius,
                        timestamp = System.currentTimeMillis(),
                    isSimulated = false,
                    address = fullAddress,
                    locationName = locationName
                    )
                    
                android.util.Log.d("LocationService", "定位成功 (isSimulating=$isSimulating, isFetchingRealLocation=$isFetchingRealLocation)")
                
                // 如果正在主动获取真实位置，即使在模拟中也更新
                if (!isSimulating || isFetchingRealLocation) {
                        _currentLocation.value = locationData
                        addToHistory(locationData)
                    android.util.Log.d("LocationService", "✓ 更新真实位置: ${location.latitude}, ${location.longitude}, 地址: $fullAddress")
                    
                    if (isFetchingRealLocation) {
                        android.util.Log.d("LocationService", "✅ 真实位置已成功获取并显示（模拟将在3秒后恢复）")
                    }
                } else {
                    android.util.Log.d("LocationService", "忽略真实位置（正在模拟中）")
                }
            } else {
                android.util.Log.w("LocationService", "定位失败: locType=${location.locType}, errorCode=${location.locType}")
            }
        }
    }
    
    private var isListenerRegistered = false
    
    private fun ensureListenerRegistered() {
        if (!isListenerRegistered) {
            android.util.Log.d("LocationService", "注册百度定位监听器")
            getBaiduLocationClient().registerLocationListener(baiduLocationListener)
            isListenerRegistered = true
        } else {
            android.util.Log.d("LocationService", "监听器已注册")
        }
    }
    
    fun hasLocationPermission(): Boolean {
        return ActivityCompat.checkSelfPermission(
            context,
            Manifest.permission.ACCESS_FINE_LOCATION
        ) == PackageManager.PERMISSION_GRANTED
    }
    
    fun getCurrentLocation() {
        if (!hasLocationPermission()) {
            android.util.Log.w("LocationService", "没有定位权限")
            return
        }
        
        android.util.Log.d("LocationService", "=== 开始获取真实位置 ===")
        android.util.Log.d("LocationService", "当前状态: isSimulating=$isSimulating")
        
        // 设置标志：正在获取真实位置
        isFetchingRealLocation = true
        
        if (isSimulating) {
            android.util.Log.d("LocationService", "⚠️ 正在模拟中，暂时移除 Mock Provider 以获取真实位置")
            
            // 暂时移除 mock provider
            mockLocationProvider.removeMockLocationProvider()
            
            // 等待 500ms 让系统切换回真实定位
            android.os.Handler(android.os.Looper.getMainLooper()).postDelayed({
                android.util.Log.d("LocationService", "开始获取真实位置...")
                ensureListenerRegistered()
                getBaiduLocationClient().start()
                
                // 获取真实位置后，3秒后恢复模拟
                android.os.Handler(android.os.Looper.getMainLooper()).postDelayed({
                    if (isSimulating) {
                        android.util.Log.d("LocationService", "✅ 真实位置已获取，恢复模拟位置")
                        isFetchingRealLocation = false
                        mockLocationProvider.addMockLocationProvider()
                        mockLocationProvider.setMockLocation(
                            currentMockLatitude,
                            currentMockLongitude,
                            currentMockAccuracy
                        )
                    } else {
                        isFetchingRealLocation = false
                    }
                }, 3000)
            }, 500)
        } else {
            // 没有在模拟，直接获取真实位置
            android.util.Log.d("LocationService", "直接获取真实位置")
            ensureListenerRegistered()
            getBaiduLocationClient().start()
            
            // 3秒后清除标志
            android.os.Handler(android.os.Looper.getMainLooper()).postDelayed({
                isFetchingRealLocation = false
            }, 3000)
        }
    }
    
    fun startLocationUpdates() {
        if (!hasLocationPermission()) {
            return
        }
        
        if (!isSimulating) {
            // 确保监听器已注册
            ensureListenerRegistered()
            // 修改为连续定位
            getBaiduLocationClient().locOption = LocationClientOption().apply {
                locationMode = LocationClientOption.LocationMode.Hight_Accuracy
                setCoorType("bd09ll")
                setScanSpan(5000) // 5秒定位一次
                setIsNeedAddress(true)
            }
            getBaiduLocationClient().start()
        }
    }
    
    fun stopLocationUpdates() {
        _baiduLocationClient?.stop()
    }
    
    fun simulateLocation(latitude: Double, longitude: Double) {
        val simulatedLocationData = LocationData(
            latitude = latitude,
            longitude = longitude,
            accuracy = 5.0f,
            timestamp = System.currentTimeMillis(),
            isSimulated = true,
            address = "获取地址中...",
            locationName = ""
        )
        
        simulatedLocation = simulatedLocationData
        isSimulating = true
        
        // 先显示位置（没有地址）
        _currentLocation.value = simulatedLocationData
        
        // 异步获取地址信息
        android.util.Log.d("LocationService", "开始反向地理编码: $latitude, $longitude")
        pendingLocationData = simulatedLocationData
        geoCoder.reverseGeoCode(ReverseGeoCodeOption()
            .location(LatLng(latitude, longitude))
            .newVersion(1)
            .radius(500))
    }
    
    /**
     * 启用系统级Mock Location（其他应用也能获取到）
     */
    fun enableSystemMockLocation(): Boolean {
        return mockLocationProvider.addMockLocationProvider()
    }
    
    /**
     * 设置系统级Mock位置
     */
    fun setSystemMockLocation(latitude: Double, longitude: Double, accuracy: Float = 5.0f) {
        android.util.Log.d("LocationService", "=== 开始设置系统模拟位置 ===")
        android.util.Log.d("LocationService", "坐标: $latitude, $longitude, 精度: $accuracy")
        
        // 保存当前模拟坐标
        currentMockLatitude = latitude
        currentMockLongitude = longitude
        currentMockAccuracy = accuracy
        
        // 确保Mock Provider已添加
        val mockEnabled = mockLocationProvider.addMockLocationProvider()
        android.util.Log.d("LocationService", "Mock Provider状态: $mockEnabled")
        
        if (!mockEnabled) {
            android.util.Log.e("LocationService", "❌ 无法添加Mock Provider，请检查权限")
            return
        }
        
        // 设置模拟位置
        mockLocationProvider.setMockLocation(latitude, longitude, accuracy)
        android.util.Log.d("LocationService", "✓ 已调用setMockLocation")
        
        val simulatedLocationData = LocationData(
            latitude = latitude,
            longitude = longitude,
            accuracy = accuracy,
            timestamp = System.currentTimeMillis(),
            isSimulated = true,
            address = "获取地址中...",
            locationName = ""
        )
        
        simulatedLocation = simulatedLocationData
        isSimulating = true
        
        // 先显示位置（没有地址）
        _currentLocation.value = simulatedLocationData
        
        // 🔥 启动前台服务，确保后台也能持续更新
        android.util.Log.d("LocationService", "🚀 启动前台服务进行持续更新")
        LocationForegroundService.start(context, latitude, longitude, accuracy)
        
        // 异步获取地址信息
        android.util.Log.d("LocationService", "开始反向地理编码: $latitude, $longitude")
        pendingLocationData = simulatedLocationData
        geoCoder.reverseGeoCode(ReverseGeoCodeOption()
            .location(LatLng(latitude, longitude))
            .newVersion(1)
            .radius(500))
    }
    
    /**
     * 持续更新模拟位置（每秒一次）
     * 某些应用需要持续的位置更新才能正常显示
     */
    private fun startContinuousLocationUpdate() {
        // 取消之前的任务
        updateLocationJob?.cancel()
        
        android.util.Log.d("LocationService", "==== 启动持续位置更新任务 ====")
        android.util.Log.d("LocationService", "模拟坐标: $currentMockLatitude, $currentMockLongitude")
        
        updateLocationJob = serviceScope.launch {
            var updateCount = 0
            android.util.Log.d("LocationService", "后台协程已启动，开始持续更新")
            
            while (isActive && isSimulating) {
                try {
                    updateCount++
                    
                    // 每秒更新一次位置
                    mockLocationProvider.setMockLocation(
                        currentMockLatitude,
                        currentMockLongitude,
                        currentMockAccuracy
                    )
                    
                    // 每5次更新输出一次日志（避免日志过多）
                    if (updateCount % 5 == 0) {
                        android.util.Log.d("LocationService", "已持续更新 $updateCount 次，协程运行正常")
                    }
                    
                    delay(1000) // 1秒
                } catch (e: Exception) {
                    android.util.Log.e("LocationService", "持续更新位置失败: ${e.message}")
                    e.printStackTrace()
                }
            }
            android.util.Log.d("LocationService", "持续位置更新任务已停止 (总更新 $updateCount 次)")
        }
        
        android.util.Log.d("LocationService", "协程任务已提交，Job=$updateLocationJob")
    }
    
    /**
     * 停止持续更新位置
     */
    private fun stopContinuousLocationUpdate() {
        updateLocationJob?.cancel()
        updateLocationJob = null
        android.util.Log.d("LocationService", "已停止持续位置更新")
    }
    
    /**
     * 禁用系统级Mock Location
     */
    fun disableSystemMockLocation() {
        android.util.Log.d("LocationService", "停止系统级模拟位置")
        
        // 🔥 停止前台服务
        android.util.Log.d("LocationService", "🛑 停止前台服务")
        LocationForegroundService.stop(context)
        
        mockLocationProvider.stopMockLocation()
        isSimulating = false
        simulatedLocation = null
        
        // 立即更新UI状态 - 如果有当前位置，标记为非模拟状态
        _currentLocation.value?.let { currentLoc ->
            val updatedLocation = currentLoc.copy(isSimulated = false)
            _currentLocation.value = updatedLocation
            android.util.Log.d("LocationService", "更新位置状态为非模拟")
        }
        
        android.util.Log.d("LocationService", "清除模拟状态，准备获取真实位置")
        getCurrentLocation() // 获取真实位置
    }
    
    /**
     * 搜索地址并返回结果（使用POI搜索，支持模糊匹配）
     * @param keyword 要搜索的关键词
     * @param callback 搜索结果回调
     */
    fun searchAddress(
        keyword: String,
        callback: (List<com.example.munidingwei.ui.components.SearchResult>) -> Unit
    ) {
        android.util.Log.d("LocationService", "🔍 开始搜索地址: $keyword")
        
        if (keyword.isBlank()) {
            android.util.Log.w("LocationService", "搜索关键词为空")
            callback(emptyList())
            return
        }
        
        // 设置搜索结果回调
        onSearchResultCallback = callback
        
        try {
            // 使用POI搜索，支持模糊匹配
            val poiSearch = PoiSearch.newInstance()
            poiSearch.setOnGetPoiSearchResultListener(poiSearchListener)
            
            // 创建搜索选项
            val searchOption = PoiCitySearchOption()
                .city("全国")  // 全国范围搜索
                .keyword(keyword)  // 搜索关键词
                .pageNum(0)  // 第一页
                .pageCapacity(20)  // 每页20个结果
            
            android.util.Log.d("LocationService", "发起POI搜索请求: $keyword")
            poiSearch.searchInCity(searchOption)
            
        } catch (e: Exception) {
            android.util.Log.e("LocationService", "POI搜索异常", e)
            callback(emptyList())
        }
    }
    
    /**
     * 检查系统Mock设置状态
     */
    fun getSystemMockStatus(): String {
        return mockLocationProvider.getSystemMockStatus()
    }
    
    /**
     * 检查是否有Mock Location权限
     */
    fun hasMockLocationPermission(): Boolean {
        return mockLocationProvider.hasMockLocationPermission()
    }
    
    /**
     * 检查系统是否启用了Mock Location
     */
    fun isSystemMockEnabled(): Boolean {
        return mockLocationProvider.isSystemMockEnabled.value
    }
    
    fun stopSimulation() {
        // 同时停止系统级模拟位置
        disableSystemMockLocation()
    }
    
    fun isLocationSimulated(): Boolean = isSimulating
    
    private fun addToHistory(locationData: LocationData) {
        val currentHistory = _locationHistory.value.toMutableList()
        currentHistory.add(locationData)
        
        // 只保留最近100个位置记录
        if (currentHistory.size > 100) {
            currentHistory.removeAt(0)
        }
        
        _locationHistory.value = currentHistory
        
        // 自动上报位置到后台（如果已连接）
        reportLocationToBackend(locationData)
    }
    
    fun clearHistory() {
        _locationHistory.value = emptyList()
    }
    
    fun getLocationHistory(): List<LocationData> = _locationHistory.value
}
